from datetime import datetime

from django import forms
from django.contrib.auth.decorators import login_required
from django.db.models import Q
from django.http import HttpResponse, HttpResponseRedirect, Http404, HttpResponseServerError
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.views.generic.list_detail import object_list
from django.shortcuts import get_object_or_404
from django.core.urlresolvers import reverse

from popboard.models import Thread, Post, Category, WatchList, ForumProfile
from popboard.forms import PostForm, ThreadForm, ForumProfileForm
from popboard.helpers import is_user_moderator

class DummyUserProfile(object):
    def __init__(self):
        self.ppp = 20
        self.tpp = 20

def get_or_load_profile(request):
    """
    return the profile from the session otherwise load it
    """
    if request.user.is_authenticated():
        if not "popboard_profile" in request.session:
            forum_profile, created = ForumProfile.objects.get_or_create(user=request.user)
            request.session["popboard_profile"] = forum_profile
        return request.session["popboard_profile"]
    else:
        return DummyUserProfile()

def thread(request, thread_id):
    """
    Show the posts in a thread
    """
    forum_profile = get_or_load_profile(request)
    thread = get_object_or_404(Thread.live_objects, id=int(thread_id))
    
    if request.user.is_authenticated():
        try:
            wl = WatchList.objects.get(user=request.user, thread=thread)
            watched = True
        except WatchList.DoesNotExist:
            watched = False
            
        # increment the hit counter
        # if the user isn't the orignal author
        if thread.user != request.user:
            thread.hits += 1
            thread.save()
    else:
        watched = False

    if request.user.is_authenticated() and request.method == "POST":
        post_form = PostForm(data=request.POST)
        if post_form.is_valid():
            post_form.save_with_user(user=request.user, ip_address=request.META.get('REMOTE_ADDR', ''))
            post_form = PostForm(initial={"thread": thread.id})
    else:
        post_form = PostForm(initial={"thread": thread.id})
        
    post_list = Post.live_objects.posts_for_thread(thread_id, request.user).order_by('created')
    return object_list(request, post_list, template_object_name='post',
                           extra_context={"post_form": post_form, "watched": watched, "thread": thread},
                           template_name="popboard/thread.html",
                           paginate_by=forum_profile.ppp)

def watched_list(request):
    """
    This page shows the threads/discussions that have been marked as 'watched'
    by the user.
    """
    forum_profile = get_or_load_profile(request)
    thread_list = Thread.live_objects.get_favorites(request.user)
    return object_list(request, thread_list, template_object_name='thread',
                        template_name="popboard/watched_threads.html",
                        paginate_by=forum_profile.tpp)
watched_list = login_required(watched_list)

def new_thread(request, cat_id):
    """
    Start a new discussion.
    """
    category = get_object_or_404(Category, id=int(cat_id))

    if request.method == "POST":
        thread_form = ThreadForm(is_moderator=is_user_moderator(request.user, category),
                                 data=request.POST)
        if thread_form.is_valid():
            thread = thread_form.save_with_user(user=request.user, 
                                                ip_address=request.META.get('REMOTE_ADDR', ''), 
                                                category=category)
            return HttpResponseRedirect(thread.get_absolute_url())
    else:
        thread_form = ThreadForm(is_moderator=is_user_moderator(request.user, category),
                                 initial={"category": int(cat_id)})
    if "HTTP_REFERER" in request.META:
        return_link = request.META["HTTP_REFERER"]
    else:
        return_link = reverse('popboard-index')
    return render_to_response('popboard/new_thread.html', {'thread_form': thread_form, "return_link": return_link},
                              context_instance=RequestContext(request))
new_thread = login_required(new_thread)

def thread_category_index(request, cat_id):
    """
    Return the threads for a certain category
    """
    forum_profile = get_or_load_profile(request)
    category = get_object_or_404(Category.live_objects, id=int(cat_id))
    thread_list = Thread.live_objects.filter(category=category)
    return object_list(request, thread_list, template_object_name='thread',
                       extra_context={"category": category},
                       template_name="popboard/thread_list.html",
                        paginate_by=forum_profile.tpp)

def recent_threads(request):
    """
    Lists recently added threads
    """
    forum_profile = get_or_load_profile(request)
    thread_list = Thread.live_objects.all()
    return object_list(request, thread_list, template_object_name='thread',
                       template_name="popboard/recent_thread_list.html",
                       paginate_by=forum_profile.tpp)
                       
def recent_posts(request):
    """
    Lists recently added threads
    """
    forum_profile = get_or_load_profile(request)
    post_list = Post.live_objects.all().order_by('-created')
    return object_list(request, post_list, template_object_name='post',
                        template_name="popboard/recent_post_list.html",
                        paginate_by=forum_profile.ppp)

def category_list(request):
    """
    List all categories available on the forum
    """
    context = {}
    context['cat_list'] = Category.live_objects.all()
    context['post_count'] = Post.live_objects.all().count()
    context['topic_count'] = Thread.live_objects.all().count()
    return render_to_response('popboard/category_list.html', 
                              context,
                              context_instance=RequestContext(request))

def view_profile(request, user_id=None):
    """
    Display a users bio
    """
    if user_id:
        user_profile = get_object_or_404(ForumProfile, user__id=int(user_id))  
    elif not user_id and request.user.is_authenticated():
        user_id = request.user.id
        user_profile, created = ForumProfile.objects.get_or_create(user__id=user_id)
    else:
        return HttpResponseRedirect(reverse('popboard-index'))
        
    user_posts = Post.objects.filter(user__id=int(user_id))
    return render_to_response("popboard/user_profile.html",
                             {"user_profile": user_profile, "user_posts":user_posts},
                             context_instance=RequestContext(request))

def edit_profile(request):
    """
    Allow a user to edit their profile
    """
    forum_profile, created = ForumProfile.objects.get_or_create(user=request.user)
        
    if request.method == "POST":
        profile_form = ForumProfileForm(user=request.user, data=request.POST, instance=forum_profile)
        if profile_form.is_valid():
            forum_profile = profile_form.save()
            request.session["popboard_profile"] = forum_profile
            return HttpResponseRedirect(reverse('popboard-index'))
    else:
        profile_form = ForumProfileForm(user=request.user, instance=forum_profile)
    return render_to_response('popboard/edit_profile.html', 
                            {'profile_form': profile_form},
                            context_instance=RequestContext(request))
edit_profile = login_required(edit_profile)

def thread_status(request, thread_id):
    """
    Close/Open a thread
    """
    thread = get_object_or_404(Thread.live_objects, id=thread_id)
    if request.user.is_staff or thread.category.moderator_set.filter(user=request.user):
        if thread.closed:
            thread.closed = False
        else:
            thread.closed = True
        thread.modified = datetime.now()
        thread.save()
    return HttpResponseRedirect(thread.get_absolute_url())
thread_status = login_required(thread_status)

def thread_sticky(request, thread_id):
    """
    Set/Unset a thread as a sticky
    """
    thread = get_object_or_404(Thread.live_objects, id=thread_id)
    if request.user.is_staff or thread.category.moderator_set.filter(user=request.user):
        if thread.sticky:
            thread.sticky = False
        else:
            thread.sticky = True
        thread.modified = datetime.now()
        thread.save()
    return HttpResponseRedirect(thread.get_absolute_url())
thread_sticky = login_required(thread_sticky)

def thread_watch(request, thread_id):
    """
    Watch/Unwatch a thread
    """
    thread = get_object_or_404(Thread.live_objects, id=thread_id)
    try:
        wl = WatchList.objects.get(thread=thread, user=request.user)
        wl.delete()
    except WatchList.DoesNotExist:
        WatchList.objects.create(thread=thread, user=request.user)
    return HttpResponseRedirect(thread.get_absolute_url())
thread_watch = login_required(thread_watch)